package com.xxjqr.rbac.config;

import com.alibaba.fastjson.JSON;
import com.xxjqr.rbac.anno.IgnoreResAdvice;
import com.xxjqr.rbac.enums.CodeMsgEnum;
import com.xxjqr.rbac.exception.CommonException;
import com.xxjqr.rbac.response.Response;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;

import static com.xxjqr.rbac.enums.CodeMsgEnum.SERVER_ERROR;
import static com.xxjqr.rbac.enums.CodeMsgEnum.VALIDATE_ERROR;

/**
 * @描述  包装接口返回数据，全局异常处理
 * @码农 丁昌江
 * @日期 2021/3/2 10:24
 */
@RestControllerAdvice
public class ResultResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
        //1 如果returnType对应的类没有使用IgnoreResAdvice注解，调用的方法上也没有使用IgnoreResAdvice注解，并且返回类型也不是Response的话，就进行包装
        //2 getAnnotation内部也是调用的getDeclaredAnnotation，所以我们直接用getDeclaredAnnotation

        if (Objects.requireNonNull(returnType.getDeclaringClass()).getDeclaredAnnotation(IgnoreResAdvice.class) == null
                && Objects.requireNonNull(returnType.getMethod()).getDeclaredAnnotation(IgnoreResAdvice.class) == null
                && !returnType.getGenericParameterType().equals(Response.class)) {
            return true;
        }
        return false;
        //return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), IgnoreResAdvice.class) && !returnType.getGenericParameterType().equals(Response.class);
    }

    @Override
    public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType,
                                  final Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  final ServerHttpRequest request, final ServerHttpResponse response) {
        if (body instanceof Response) {
            return body;
        }
        final Response<Object> result = new Response<>();
        result.setCode(CodeMsgEnum.SUCESS.getCode());
        result.setMsg(CodeMsgEnum.SUCESS.getMsg());
        result.setData(body);
        //如果返回类型是String，那么把返回的字符转复制到msg中
        if (returnType.getGenericParameterType().equals(String.class)) {
            result.setMsg(body.toString());
            result.setData(null);
            return JSON.toJSONString(result);
        }
        return result;
    }


    /**
     * 处理自定义的业务异常
     * @param req 请求 request
     * @param e   异常消息实体
     * @返回 Response
     */
    @ExceptionHandler(value = CommonException.class)
    @ResponseBody
    public Response<Void> commonException(HttpServletRequest req, CommonException e) {
        CodeMsgEnum codeMsg = e.getCodeMsg();
        return Response.fail(codeMsg.getCode(), codeMsg.getMsg());
    }


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Response<Void> MethodArgumentNotValidHandler(HttpServletRequest req,
                                                        MethodArgumentNotValidException exception) throws Exception {

        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        StringJoiner sj = new StringJoiner("|");
        for (FieldError fieldError : fieldErrors) {
            //错误提示消息
            sj.add(fieldError.getDefaultMessage());
            //其他消息暂时不需要存在

            // 错误的字段
            //System.out.println(fieldError.getField());

            // 返回值
            //System.out.println(fieldError.getRejectedValue());
        }
        return Response.fail(VALIDATE_ERROR.getCode(), sj.toString());
    }


    /**
     * 处理其他异常
     * @param req 请求 request
     * @param e   异常消息实体
     * @返回 Response
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Response<Void> exceptionHandler(HttpServletRequest req, Exception e) {
        e.printStackTrace();
        return Response.fail(SERVER_ERROR.getCode(), SERVER_ERROR.getMsg());
    }


}


